package com.cn.mycodc;

import com.cn.constant.ConstantValue;
import com.cn.model.Request;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * @Author: jia
 * @Descirption:
 * @Date: 2018/5/4 16:14
 * @Modified By:
 * * 服务端解析请求：请求解码器
 * <pre>
 * 数据包格式
 * +——----——+——-----——+——----——+——----——+——-----——+——-----——+——-----——+——-----——+
 * | 包头          | 模块号        | 命令号      |  长度        |   数据       |
 * +——----——+——-----——+——----——+——----——+——-----——+——-----——+——-----——+——-----——+
 * </pre>
 * 包头4字节
 * 模块号2字节short
 * 命令号2字节short
 * 长度4字节(描述数据部分字节长度)
 */


public class MyRequestDecoder extends ByteToMessageDecoder {
    //包的基本长度
    public static int BASE_LENTH = 4 + 2 + 2 + 4;

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        //可读的字节数
        //如果可读长度大于等于基本长度往下读
        if (byteBuf.readableBytes() >= BASE_LENTH) {
            if (byteBuf.readableBytes() > 2048) {
                byteBuf.skipBytes(byteBuf.readableBytes());
            }
            //1.解析包头
            //记录包头位置
            int beginIndex;
            //一个包都是从包头开始，所以需要循环读取，直到读到包头位置，后面的顺序读取即可
            while (true){
                beginIndex=byteBuf.readerIndex();
                byteBuf.markReaderIndex();
                //如果读到包头
                if(byteBuf.readInt()== ConstantValue.FLAG){
                    break;
                }
                //恢复到标记位重新读
                byteBuf.resetReaderIndex();
                //恢复以后略过一个字节，不过不略过，就成了死循环了，一直
                //读取的不是正确的包头，每次读取的是同一个位置
                byteBuf.readByte();
                //如果可读长度变得又不满足基本长度
                if(byteBuf.readableBytes()<BASE_LENTH){
                    return;
                }

            }
            //2.解析模块号
            short module = byteBuf.readShort();
            //3.解析命令号
            short cmd = byteBuf.readShort();
            //4.解析长度
            int length = byteBuf.readInt();
            //5.解析数据
            //如果可读数据小于数据长度，回到开始位置
            if(byteBuf.readableBytes()<length){
                byteBuf.readerIndex(beginIndex);
                return;
            }
            byte[] data = new byte[length];
            //将数据读到data中
            byteBuf.readBytes(data);
            //6.解码后，设置到request中向下传递
            Request request = new Request();
            request.setModule(module);
            request.setCmd(cmd);
            request.setData(data);
            list.add(request);
        }

    }
}
